﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyFloridaHouse.libPrint.KML;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Types;

namespace MyFloridaHouse.libPrint.BingMapAjaxHelpers
{
    public static class JavaScriptBuilder
    {
        public static string GetMainMapCountiesJavaScript(string mapName, kmlDocument countyBaseLayersKml, int reduceZoomLevel)
        {
            int functionNum = 1;
            StringBuilder workingBuilder = new StringBuilder();
            var pmQuery = from pm in countyBaseLayersKml.Placemark
                          select pm;
            var pmList = pmQuery.ToList();
            foreach (var pm in pmList)
            {
                var colorString = "polygoncolor = new m.Color(0,0,0,0);";
                if (pm.MultiGeometry != null)
                {
                    var mgQuery = from mg in pm.MultiGeometry
                                  select mg;
                    var mgList = mgQuery.ToList();
                    foreach (var mg in mgList)
                    {
                        var polyQuery = from p in mg.Polygon
                                        select p;
                        var polyList = polyQuery.ToList();
                        workingBuilder.Append("function AddCountyPoly" + functionNum + "(mapName){");
                        int polyNum = 0;
                        //workingBuilder.Append("var vertices = new Array(");
                        foreach (var p in polyQuery)
                        {
                            IList<Point> polyPts = ParseCoordinates(p.outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                            //Reduce the points... YOU HAVE TO DO THIS OR BING AJAX MAY TIMEOUT
                            IList<Point> reducedPolyPts = KMLPointReduction.GeneralizePolyPoints(polyPts, reduceZoomLevel);
                            IList<Point> cleanedPolyPts = KMLPointReduction.CleanPolygons(reducedPolyPts);
                            polyPts = cleanedPolyPts;
                            SqlChars dryTorgWkt = new SqlChars("POLYGON ((-82.987476999999984 24.575284000000082, -82.7665090000001 24.575284000000082, -82.7665090000001 24.726282000000133, -82.987476999999984 24.726282000000133, -82.987476999999984 24.575284000000082))");
                            SqlGeometry dryTorgWktGeom = SqlGeometry.STGeomFromText(dryTorgWkt, 4326).MakeValid();
                            SqlChars testWkt = new SqlChars("POINT (-" + polyPts[0].Longitude + " " + polyPts[0].Latitude + ")");
                            SqlGeometry testGeom = SqlGeometry.STGeomFromText(testWkt, 4326).MakeValid().STBuffer(.005);
                            if (!testGeom.STIntersects(dryTorgWktGeom))
                            {
                                workingBuilder.Append("var vertices" + polyNum + " = new Array(");
                                int polyPointsCount = polyPts.Count();
                                int counter = 1;
                                foreach (Point pt in polyPts)
                                {
                                    if (counter < polyPointsCount)
                                    {
                                        workingBuilder.Append("new m.Location(" + pt.Latitude + ", -" + pt.Longitude + "),");
                                    }
                                    else //last one
                                    {
                                        workingBuilder.Append("new m.Location(" + pt.Latitude + ", -" + pt.Longitude + ")");
                                    }
                                    counter++;
                                }//if (!(pm.name=="Monroe") && (polyNum!=2))
                                workingBuilder.Append(");");
                                workingBuilder.Append(colorString);
                                workingBuilder.Append("var polygon" + polyNum + " = new m.Polygon(vertices" + polyNum + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                                workingBuilder.Append("mapName.entities.push(polygon" + polyNum + ");");
                            }
                            polyNum++;
                        }
                        //Now add district number
                        var centerPointCoordinates = pm.ExtendedData.centerPoint.coordinates;
                        string[] cords = centerPointCoordinates.Split(',');
                        workingBuilder.Append("var pushpin;");
                        workingBuilder.Append("var pushpinOptions;");
                        workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 20, typeName: 'countyLabel'};");
                        workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + cords[1] + ", " + cords[0] + "), pushpinOptions);");
                        workingBuilder.Append("mapName.entities.push(pushpin);");
                        int nextFunctionNum = functionNum + 1;
                        workingBuilder.Append("setTimeout('AddCountyPoly" + nextFunctionNum + "(" + mapName + ")', 1);}");
                    }//mg w/ the polys   
                }// is a mg
                else //just a poly
                {
                    var polyQuery = pm.Polygon;
                    string coords = "";
                    coords = polyQuery[0].outerBoundaryIs.linearRing.coordinates.ToString();
                    coords = coords.Replace("-", " -");
                    IList<Point> polyPts = ParseCoordinates(coords);
                    //Reduce the points... YOU HAVE TO DO THIS OR BING AJAX MAY TIMEOUT
                    IList<Point> reducedPolyPts = KMLPointReduction.GeneralizePolyPoints(polyPts, reduceZoomLevel);
                    IList<Point> cleanedPolyPts = KMLPointReduction.CleanPolygons(reducedPolyPts);
                    polyPts = cleanedPolyPts;
                    workingBuilder.Append("function AddCountyPoly" + functionNum + "(mapName){");

                    workingBuilder.Append("vertices = new Array(");
                    int polyPointsCount = polyPts.Count();
                    int counter = 1;
                    foreach (Point p in polyPts)
                    {
                        if (counter < polyPointsCount)
                        {
                            workingBuilder.Append("new m.Location(" + p.Latitude + ", -" + p.Longitude + "),");
                        }
                        else //last one
                        {
                            workingBuilder.Append("new m.Location(" + p.Latitude + ", -" + p.Longitude + ")");
                        }
                        counter++;
                    }
                    workingBuilder.Append(");");
                    workingBuilder.Append(colorString);
                    workingBuilder.Append("polygon = new m.Polygon(vertices,{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                    workingBuilder.Append("mapName.entities.push(polygon);");
                    //Now add district number
                    var centerPointCoordinates = pm.ExtendedData.centerPoint.coordinates;
                    string[] cords = centerPointCoordinates.Split(',');
                    workingBuilder.Append("var pushpin;");
                    workingBuilder.Append("var pushpinOptions;");
                    workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 40, typeName: 'countyLabel'};");
                    workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + cords[1] + ", " + cords[0] + "), pushpinOptions);");
                    workingBuilder.Append("mapName.entities.push(pushpin);");
                    int nextFunctionNum = functionNum + 1;
                    workingBuilder.Append("if (mapName==mainMap){setTimeout('AddCountyPoly" + nextFunctionNum + "(" + mapName + ")', 1);}}");
                } //just a poly
                //iterate the function number
                functionNum++;
            }//pm
            return workingBuilder.ToString();
        }


        //see this post for how to get items in linq list that are nested
        //https://varshavmane.wordpress.com/2011/02/07/how-to-get-nested-records-from-your-object-class-list-using-linq/
        public static string GetDistrictsJavaScript(string mapName, bool moreMapsLeft, kml kmlDeserialized, int reduceZoomLevel)
        {
            string returnString = "";
            string documentName;
            int mgNum = 1;

            StringBuilder workingBuilder = new StringBuilder();
            documentName = kmlDeserialized.Items[0].name;
            var pmQuery = from pm in kmlDeserialized.Items[0].Placemark
                          select pm;
            var pmList = pmQuery.ToList();
            foreach (var pm in pmList)
            {
                string hexColor = pm.Style[0].PolyStyle[0].color;
                hexColor = hexColor.Replace(@"#", String.Empty);
                var districtColors = new PreDefinedColorsForBingAjax(); //using this for livSvUtilities
                System.Drawing.Color rgbColor = System.Drawing.ColorTranslator.FromHtml("#" + districtColors.GetColorFromIndex(Int32.Parse(pm.name)));
                string colorString = "polygoncolor = new m.Color(100," + rgbColor.R.ToString() + "," + rgbColor.G.ToString() + "," + rgbColor.B.ToString() + ");";
                var mgQuery = from mg in pm.MultiGeometry
                              select mg;
                var mgList = mgQuery.ToList();
                foreach (var mg in mgList) //taking it one multi-geometry at a time
                {
                    var polyQuery = from p in mg.Polygon
                                    select p;
                    var polyList = polyQuery.ToList();
                    workingBuilder.Append("function AddPoly" + mgNum + "(mapName){");
                    int polyNum = 0;
                    foreach (var p in polyQuery)
                    {

                        IList<Point> polyPts = ParseCoordinates(p.outerBoundaryIs.linearRing.coordinates.ToString());
                        //Reduce the points... YOU HAVE TO DO THIS OR BING AJAX MAY TIMEOUT
                        IList<Point> reducedPolyPts = KMLPointReduction.GeneralizePolyPoints(polyPts, reduceZoomLevel);
                        IList<Point> cleanedPolyPts = KMLPointReduction.CleanPolygons(reducedPolyPts);
                        polyPts = cleanedPolyPts;
                        //POLYGON ((-82.987476999999984 24.575284000000082, -82.7665090000001 24.575284000000082, -82.7665090000001 24.726282000000133, -82.987476999999984 24.726282000000133, -82.987476999999984 24.575284000000082))
                        SqlChars dryTorgWkt = new SqlChars("POLYGON ((-82.987476999999984 24.575284000000082, -82.7665090000001 24.575284000000082, -82.7665090000001 24.726282000000133, -82.987476999999984 24.726282000000133, -82.987476999999984 24.575284000000082))");
                        SqlGeometry dryTorgWktGeom = SqlGeometry.STGeomFromText(dryTorgWkt, 4326).MakeValid();
                        SqlChars testWkt = new SqlChars("POINT (-" + polyPts[0].Longitude + " " + polyPts[0].Latitude + ")");
                        SqlGeometry testGeom = SqlGeometry.STGeomFromText(testWkt, 4326).MakeValid().STBuffer(.005);
                        if (!testGeom.STIntersects(dryTorgWktGeom))
                        {
                            workingBuilder.Append("var vertices" + polyNum + " = new Array(");
                            int polyPointsCount = polyPts.Count();
                            int counter = 1;
                            foreach (Point pt in polyPts)
                            {
                                if (counter < polyPointsCount)
                                {
                                    workingBuilder.Append("new m.Location(" + pt.Latitude + ", -" + pt.Longitude + "),");
                                }
                                else //last one
                                {
                                    workingBuilder.Append("new m.Location(" + pt.Latitude + ", -" + pt.Longitude + ")");
                                }
                                counter++;
                            }
                            workingBuilder.Append(");");
                            workingBuilder.Append(colorString);
                            workingBuilder.Append("var polygon" + polyNum + " = new m.Polygon(vertices" + polyNum + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                            workingBuilder.Append("mapName.entities.push(polygon" + polyNum + ");");
                        }//if (!(pm.name == "Monroe") && (polyNum != 2))
                        polyNum++;
                    }//foreach (var p in polyQuery)

                    //Done adding polygons now we will try to add the district number
                    string[] centerPoints = pm.ExtendedData.centerPoint.coordinates.Split(new Char[] { ',', ' ' });

                    //SqlGeometry centerPoint = simplePolygonCentroid(districtBoxGeom);

                    //Manual fix method by eye-balling displacement
                    double fixDisplacementX = double.Parse(centerPoints[0]) + .01;
                    double fixDisplacementY = double.Parse(centerPoints[1]) - .1;
                    //workingBuilder.Append("var pushpinOptions = { icon: '../images/"+currentDistrictNumber+".png', height: 20, width: 20, anchor: new m.Point(" + fixDisplacementX + ", " + fixDisplacementY + ")};");
                    //var pushpinOptions = { icon: '../images/blank.png', text: 'this is a test', height: 50, width: 50, anchor: new m.Point(-86.3947038675, 30.6501557915) };
                    workingBuilder.Append("var pushpin;");
                    workingBuilder.Append("var pushpinOptions;");
                    workingBuilder.Append("if (mapName==mainMap){pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 20, typeName: 'districtLabel'};}");
                    workingBuilder.Append("if (mapName==mainMap){pushpin = new m.Pushpin(new m.Location(" + fixDisplacementY + ", " + fixDisplacementX + "), pushpinOptions);}");
                    workingBuilder.Append("if (mapName!=mainMap){pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 20, typeName: 'districtLabel'};}");
                    workingBuilder.Append("if (mapName!=mainMap){pushpin = new m.Pushpin(new m.Location(" + centerPoints[1] + ", " + centerPoints[0] + "), pushpinOptions);}");

                    //Method described in Bing Map Ajax forum posting http://social.msdn.microsoft.com/Forums/en/vemapcontroldev/thread/29fabfc8-dc6e-4b35-a27b-d95ed19c4472
                    //workingBuilder.Append("var pushpinOptions = { icon: '../images/" + currentDistrictNumber + ".png', height: 20, width: 20, anchor: new m.Point(1, 3)};");
                    //workingBuilder.Append("var pushpin = new m.Pushpin(new m.Location(" + centerPoints[1] + ", " + centerPoints[0] + "), pushpinOptions);");

                    //workingBuilder.Append("var pushpin = new m.Pushpin(new m.Location(" + centerPoint.STY.ToString() + ", " + centerPoint.STX.ToString() + "), pushpinOptions);");
                    workingBuilder.Append("mapName.entities.push(pushpin);");

                    int nextMg = mgNum + 1;
                    workingBuilder.Append("if (mapName==mainMap){setTimeout('AddPoly" + nextMg + "(" + mapName + ")', 1);}}");
                    mgNum++;
                }//mg w/ the polys                
            }//pm
            if (!moreMapsLeft)
            {
                workingBuilder.Append("function AddPoly" + mgNum + "(mapName){if (mapName==mainMap){setTimeout('AddCountyPoly1(" + mapName + ")', 100);}}");
                //workingBuilder.Append("function AddPoly" + mgNum + "(mapName){if (mapName==mainMap){}}");
            }
            else
            {
                int nextMg = mgNum + 1;
                //workingBuilder.Append("function AddPoly" + mgNum + "(){alert('Districts for " + mapName + " Loaded');AddPoly" + nextMg + "();}");
                workingBuilder.Append("function AddPoly" + mgNum + "(mapName){{if (mapName==mainMap){AddPoly" + nextMg + "(mapName);}}");
            }
            returnString = workingBuilder.ToString();
            //bool mainMapLoaded = true;
            return returnString;
        }


        public static string GetMapInsetCountiesJavaScript(string mapName, Point[] mapInsetBoxPts, kmlDocument kmlDeserialized)
        {
            string returnString = "";
            int pmNum = 1;
            var colorString = "polygoncolor = new m.Color(0,0,0,0);";
            StringBuilder workingBuilder = new StringBuilder();
            var pmQuery = from pm in kmlDeserialized.Placemark
                          select pm;
            var pmList = pmQuery.ToList();
            foreach (var pm in pmList)
            {
                Point[] countyBoxPts = new Point[2];
                countyBoxPts[0] = new Point(double.Parse(pm.ExtendedData.latLonAltBox.west), double.Parse(pm.ExtendedData.latLonAltBox.north));
                countyBoxPts[1] = new Point(double.Parse(pm.ExtendedData.latLonAltBox.east), double.Parse(pm.ExtendedData.latLonAltBox.south));
                //Now we need to check the shape by the map bounding box
                //NW and SE is all that is needed
                SqlGeometry mapBoxGeom = new SqlGeometry();
                SqlChars mapBoxWkt = new SqlChars("LINESTRING(" + mapInsetBoxPts[0].Longitude + " " + mapInsetBoxPts[0].Latitude + ", " + mapInsetBoxPts[1].Longitude + " " + mapInsetBoxPts[1].Latitude + ")");
                mapBoxGeom = SqlGeometry.STGeomFromText(mapBoxWkt, 4326);

                SqlGeometry countyBoxGeom = new SqlGeometry();
                SqlChars countyBoxWkt = new SqlChars("LINESTRING(" + countyBoxPts[0].Longitude + " " + countyBoxPts[0].Latitude + ", " + countyBoxPts[1].Longitude + " " + countyBoxPts[1].Latitude + ")");
                countyBoxGeom = SqlGeometry.STGeomFromText(countyBoxWkt, 4326);
                if (pm.MultiGeometry != null) //multi-poly
                {
                    var mgQuery = from mg in pm.MultiGeometry
                                  select mg;
                    var mgList = mgQuery.ToList();
                    foreach (var mg in mgList) //taking it one multi-geometry at a time
                    {
                        if (countyBoxGeom.STEnvelope().STIntersects(mapBoxGeom.STEnvelope())) //the district is intersected
                        { //only put the district in via existing javascript function if it is within view of the map
                            var polyQuery = from p in mg.Polygon
                                            select p;
                            var polyList = polyQuery.ToList();
                            workingBuilder.Append("function AddCountyPoly" + mapName + pmNum + "(mapName){");
                            int originalPolyNum = 0;
                            foreach (var p in polyQuery)
                            {
                                IList<Point> polyPts = ParseCoordinates(p.outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                //get the up the district shape that is intersected w/ the bounding box
                                SqlGeometry clippedGeom = CreateClippedPolyFromBoundingBox(polyPts, mapBoxGeom);
                                //Need to handle the case of GEOMETRYCOLLECTION EMPTY... meaning there is no intersection here
                                if (!clippedGeom.STAsText().ToSqlString().ToString().Contains("EMPTY"))
                                {
                                    SqlString clippedKmlShape = KMLFunctions.ExportWKTToKml((SqlString)clippedGeom.STAsText());
                                    kml clippedKmlShapeDeserialized = KMLSerialFunctions.DeserializeKML(clippedKmlShape.ToString().Replace(@"\", String.Empty));
                                    if (clippedGeom.STAsText().ToSqlString().ToString().Contains("MULTIPOLYGON"))
                                    {
                                        var polyQuery2 = from p2 in clippedKmlShapeDeserialized.Items[0].Placemark[0].MultiGeometry[0].Polygon
                                                         select p2;
                                        var polyList2 = polyQuery2.ToList();
                                        int poly2Num = 0;
                                        foreach (var p2 in polyQuery2)
                                        {
                                            polyPts = ParseCoordinates(clippedKmlShapeDeserialized.Items[0].Placemark[0].MultiGeometry[0].Polygon[poly2Num].outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                            int polyPointsCount = polyPts.Count();
                                            if (polyPointsCount > 0)
                                            {
                                                workingBuilder.Append("var vertices" + originalPolyNum + poly2Num + " = new Array(");
                                                foreach (Point pt in polyPts)
                                                {
                                                    workingBuilder.Append("new m.Location(" + pt.Latitude + ", " + pt.Longitude + "),");
                                                }
                                                workingBuilder.Remove(workingBuilder.Length - 1, 1);  //remove last comma
                                                workingBuilder.Append(");");
                                                workingBuilder.Append(colorString);
                                                workingBuilder.Append("var polygon" + originalPolyNum + poly2Num + " = new m.Polygon(vertices" + originalPolyNum + poly2Num + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                                                workingBuilder.Append("mapName.entities.push(polygon" + originalPolyNum + poly2Num + ");");
                                            }
                                            poly2Num++;
                                        }
                                        //Now add district number
                                        var centerPoint = GetLabelLocation(clippedGeom);
                                        workingBuilder.Append("var pushpin;");
                                        workingBuilder.Append("var pushpinOptions;");
                                        workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 40, typeName: 'countyLabel'};");
                                        workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + centerPoint.Latitude + ", " + centerPoint.Longitude + "), pushpinOptions);");
                                        workingBuilder.Append("mapName.entities.push(pushpin);");
                                    }
                                    else
                                    {
                                        //(p.outerBoundaryIs.linearRing.coordinates.ToString());
                                        polyPts = ParseCoordinates(clippedKmlShapeDeserialized.Items[0].Placemark[0].Polygon[0].outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                        int polyPointsCount = polyPts.Count();
                                        workingBuilder.Append("var vertices" + originalPolyNum + " = new Array(");
                                        foreach (Point pt in polyPts)
                                        {
                                            workingBuilder.Append("new m.Location(" + pt.Latitude + ", " + pt.Longitude + "),");
                                        }
                                        workingBuilder.Remove(workingBuilder.Length - 1, 1);  //remove last comma
                                        workingBuilder.Append(");");
                                        workingBuilder.Append(colorString);
                                        workingBuilder.Append("var polygon" + originalPolyNum + " = new m.Polygon(vertices" + originalPolyNum + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                                        workingBuilder.Append("mapName.entities.push(polygon" + originalPolyNum + ");");
                                        //Now add district number
                                        var centerPoint = GetLabelLocation(clippedGeom);
                                        workingBuilder.Append("var pushpin;");
                                        workingBuilder.Append("var pushpinOptions;");
                                        workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 40, typeName: 'countyLabel'};");
                                        workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + centerPoint.Latitude + ", " + centerPoint.Longitude + "), pushpinOptions);");
                                        workingBuilder.Append("mapName.entities.push(pushpin);");
                                    }
                                } // if not empty
                                originalPolyNum++;
                            }//foreach (var p in polyQuery)
                            workingBuilder.Append("}");
                            workingBuilder.Append("setTimeout('AddCountyPoly" + mapName + pmNum + "(" + mapName + ")', 1);");
                        } //(districtBoxGeom.STEnvelope().STIntersects(mapBoxGeom.STEnvelope()))
                    }//mg w/ the polys    
                }
                else //Just a poly
                {
                    if (countyBoxGeom.STEnvelope().STIntersects(mapBoxGeom.STEnvelope())) //the district is intersected
                    { //only put the district in via existing javascript function if it is within view of the map
                        if (countyBoxGeom.STEnvelope().STWithin(mapBoxGeom.STEnvelope()))
                        {
                            workingBuilder.Append("setTimeout('AddCountyPoly" + pmNum + "(" + mapName + ")', 1);");
                        }
                        else //not within the map inset box but apperently it intersects
                        {
                            var polyQuery = from p in pm.Polygon
                                            select p;
                            var polyList = polyQuery.ToList();
                            workingBuilder.Append("function AddCountyPoly" + mapName + pmNum + "(mapName){");
                            int originalPolyNum = 0;
                            foreach (var p in polyQuery)
                            {
                                IList<Point> polyPts = ParseCoordinates(p.outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                //get the up the district shape that is intersected w/ the bounding box
                                SqlGeometry clippedGeom = CreateClippedPolyFromBoundingBox(polyPts, mapBoxGeom);
                                //Need to handle the case of GEOMETRYCOLLECTION EMPTY... meaning there is no intersection here
                                if (!clippedGeom.STAsText().ToSqlString().ToString().Contains("EMPTY"))
                                {
                                    SqlString clippedKmlShape = KMLFunctions.ExportWKTToKml((SqlString)clippedGeom.STAsText());
                                    kml clippedKmlShapeDeserialized = KMLSerialFunctions.DeserializeKML(clippedKmlShape.ToString().Replace(@"\", String.Empty));
                                    if (clippedGeom.STAsText().ToSqlString().ToString().Contains("MULTIPOLYGON"))
                                    {
                                        var polyQuery2 = from p2 in clippedKmlShapeDeserialized.Items[0].Placemark[0].MultiGeometry[0].Polygon
                                                         select p2;
                                        var polyList2 = polyQuery2.ToList();
                                        int poly2Num = 0;
                                        foreach (var p2 in polyQuery2)
                                        {
                                            polyPts = ParseCoordinates(clippedKmlShapeDeserialized.Items[0].Placemark[0].MultiGeometry[0].Polygon[poly2Num].outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                            int polyPointsCount = polyPts.Count();
                                            if (polyPointsCount > 0)
                                            {
                                                workingBuilder.Append("var vertices" + originalPolyNum + poly2Num + " = new Array(");
                                                foreach (Point pt in polyPts)
                                                {
                                                    workingBuilder.Append("new m.Location(" + pt.Latitude + ", " + pt.Longitude + "),");
                                                }
                                                workingBuilder.Remove(workingBuilder.Length - 1, 1);  //remove last comma
                                                workingBuilder.Append(");");
                                                workingBuilder.Append(colorString);
                                                workingBuilder.Append("var polygon" + originalPolyNum + poly2Num + " = new m.Polygon(vertices" + originalPolyNum + poly2Num + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                                                workingBuilder.Append("mapName.entities.push(polygon" + originalPolyNum + poly2Num + ");");
                                            }
                                            poly2Num++;
                                        }
                                        //Now add district number
                                        var centerPoint = GetLabelLocation(clippedGeom);
                                        workingBuilder.Append("var pushpin;");
                                        workingBuilder.Append("var pushpinOptions;");
                                        workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 40, typeName: 'countyLabel'};");
                                        workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + centerPoint.Latitude + ", " + centerPoint.Longitude + "), pushpinOptions);");
                                        workingBuilder.Append("mapName.entities.push(pushpin);");
                                    }
                                    else
                                    {
                                        //(p.outerBoundaryIs.linearRing.coordinates.ToString());
                                        polyPts = ParseCoordinates(clippedKmlShapeDeserialized.Items[0].Placemark[0].Polygon[0].outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                        int polyPointsCount = polyPts.Count();
                                        workingBuilder.Append("var vertices" + originalPolyNum + " = new Array(");
                                        foreach (Point pt in polyPts)
                                        {
                                            workingBuilder.Append("new m.Location(" + pt.Latitude + ", " + pt.Longitude + "),");
                                        }
                                        workingBuilder.Remove(workingBuilder.Length - 1, 1);  //remove last comma
                                        workingBuilder.Append(");");
                                        workingBuilder.Append(colorString);
                                        workingBuilder.Append("var polygon" + originalPolyNum + " = new m.Polygon(vertices" + originalPolyNum + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                                        workingBuilder.Append("mapName.entities.push(polygon" + originalPolyNum + ");");
                                        //Now add district number
                                        var centerPoint = GetLabelLocation(clippedGeom);
                                        workingBuilder.Append("var pushpin;");
                                        workingBuilder.Append("var pushpinOptions;");
                                        workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 40, typeName: 'countyLabel'};");
                                        workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + centerPoint.Latitude + ", " + centerPoint.Longitude + "), pushpinOptions);");
                                        workingBuilder.Append("mapName.entities.push(pushpin);");
                                    }
                                } // if not empty
                                originalPolyNum++;
                            }//foreach (var p in polyQuery)
                            workingBuilder.Append("}");
                            workingBuilder.Append("setTimeout('AddCountyPoly" + mapName + pmNum + "(" + mapName + ")', 1);");
                        }//else district is not within
                    } //(districtBoxGeom.STEnvelope().STIntersects(mapBoxGeom.STEnvelope()))
                }
                int nextPm = pmNum + 1;
                pmNum++;
            } //foreach (var pm in pmList)
            returnString = workingBuilder.ToString();
            return returnString;
        }

        /// <summary>
        /// Gets the map inset java script.
        /// </summary>
        /// <returns></returns>
        public static string GetMapInsetDistrictsJavaScript(string mapName, Point[] mapInsetBoxPts, kml kmlDeserialized)
        {
            string returnString = "";
            int mgNum = 1;
            StringBuilder workingBuilder = new StringBuilder();
            var pmQuery = from pm in kmlDeserialized.Items[0].Placemark
                          select pm;
            var pmList = pmQuery.ToList();
            foreach (var pm in pmList)
            {
                Point[] districtBoxPts = new Point[2];
                districtBoxPts[0] = new Point(double.Parse(pm.ExtendedData.latLonAltBox.west), double.Parse(pm.ExtendedData.latLonAltBox.north));
                districtBoxPts[1] = new Point(double.Parse(pm.ExtendedData.latLonAltBox.east), double.Parse(pm.ExtendedData.latLonAltBox.south));
                //Now we need to check the shape by the map bounding box
                //NW and SE is all that is needed
                SqlGeometry mapBoxGeom = new SqlGeometry();
                SqlChars mapBoxWkt = new SqlChars("LINESTRING(" + mapInsetBoxPts[0].Longitude + " " + mapInsetBoxPts[0].Latitude + ", " + mapInsetBoxPts[1].Longitude + " " + mapInsetBoxPts[1].Latitude + ")");
                mapBoxGeom = SqlGeometry.STGeomFromText(mapBoxWkt, 4326);

                SqlGeometry districtBoxGeom = new SqlGeometry();
                SqlChars districtBoxWkt = new SqlChars("LINESTRING(" + districtBoxPts[0].Longitude + " " + districtBoxPts[0].Latitude + ", " + districtBoxPts[1].Longitude + " " + districtBoxPts[1].Latitude + ")");
                districtBoxGeom = SqlGeometry.STGeomFromText(districtBoxWkt, 4326);

                var mgQuery = from mg in pm.MultiGeometry
                              select mg;
                var mgList = mgQuery.ToList();
                foreach (var mg in mgList) //taking it one multi-geometry at a time
                {
                    if (districtBoxGeom.STEnvelope().STIntersects(mapBoxGeom.STEnvelope())) //the district is intersected
                    { //only put the district in via existing javascript function if it is within view of the map
                        string hexColor = pm.Style[0].PolyStyle[0].color;
                        hexColor = hexColor.Replace(@"#", String.Empty);
                        var districtColors = new PreDefinedColorsForBingAjax(); //using this for livSvUtilities
                        System.Drawing.Color rgbColor = System.Drawing.ColorTranslator.FromHtml("#" + districtColors.GetColorFromIndex(Int32.Parse(pm.name)));
                        string colorString = "polygoncolor = new m.Color(100," + rgbColor.R.ToString() + "," + rgbColor.G.ToString() + "," + rgbColor.B.ToString() + ");";
                        var polyQuery = from p in mg.Polygon
                                        select p;
                        var polyList = polyQuery.ToList();
                        workingBuilder.Append("function AddPoly" + mapName + mgNum + "(mapName){");
                        int originalPolyNum = 0;
                        foreach (var p in polyQuery)
                        {
                            IList<Point> polyPts = ParseCoordinates(p.outerBoundaryIs.linearRing.coordinates.ToString());
                            //get the up the district shape that is intersected w/ the bounding box
                            SqlGeometry clippedGeom = CreateClippedPolyFromBoundingBox(polyPts, mapBoxGeom);
                            //Need to handle the case of GEOMETRYCOLLECTION EMPTY... meaning there is no intersection here
                            if (!clippedGeom.STAsText().ToSqlString().ToString().Contains("EMPTY"))
                            {
                                SqlString clippedKmlShape = KMLFunctions.ExportWKTToKml((SqlString)clippedGeom.STAsText());
                                kml clippedKmlShapeDeserialized = KMLSerialFunctions.DeserializeKML(clippedKmlShape.ToString().Replace(@"\", String.Empty));
                                if (clippedGeom.STAsText().ToSqlString().ToString().Contains("MULTIPOLYGON"))
                                {
                                    var polyQuery2 = from p2 in clippedKmlShapeDeserialized.Items[0].Placemark[0].MultiGeometry[0].Polygon
                                                     select p2;
                                    var polyList2 = polyQuery2.ToList();
                                    int poly2Num = 0;
                                    foreach (var p2 in polyQuery2)
                                    {
                                        polyPts = ParseCoordinates(clippedKmlShapeDeserialized.Items[0].Placemark[0].MultiGeometry[0].Polygon[poly2Num].outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                        int polyPointsCount = polyPts.Count();
                                        if (polyPointsCount > 0)
                                        {
                                            workingBuilder.Append("var vertices" + originalPolyNum + poly2Num + " = new Array(");
                                            foreach (Point pt in polyPts)
                                            {
                                                workingBuilder.Append("new m.Location(" + pt.Latitude + ", " + pt.Longitude + "),");
                                            }
                                            workingBuilder.Remove(workingBuilder.Length - 1, 1);  //remove last comma
                                            workingBuilder.Append(");");
                                            workingBuilder.Append(colorString);
                                            workingBuilder.Append("var polygon" + originalPolyNum + poly2Num + " = new m.Polygon(vertices" + originalPolyNum + poly2Num + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                                            workingBuilder.Append("mapName.entities.push(polygon" + originalPolyNum + poly2Num + ");");
                                        }
                                        poly2Num++;
                                    }
                                    //Now add district number
                                    var centerPoint = GetLabelLocation(clippedGeom);
                                    workingBuilder.Append("var pushpin;");
                                    workingBuilder.Append("var pushpinOptions;");
                                    workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 20, typeName: 'districtLabel'};");
                                    workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + centerPoint.Latitude + ", " + centerPoint.Longitude + "), pushpinOptions);");
                                    workingBuilder.Append("mapName.entities.push(pushpin);");
                                }
                                else
                                {
                                    //(p.outerBoundaryIs.linearRing.coordinates.ToString());
                                    polyPts = ParseCoordinates(clippedKmlShapeDeserialized.Items[0].Placemark[0].Polygon[0].outerBoundaryIs.linearRing.coordinates.ToString().Replace("-", " -"));
                                    int polyPointsCount = polyPts.Count();
                                    workingBuilder.Append("var vertices" + originalPolyNum + " = new Array(");
                                    foreach (Point pt in polyPts)
                                    {
                                        workingBuilder.Append("new m.Location(" + pt.Latitude + ", " + pt.Longitude + "),");
                                    }
                                    workingBuilder.Remove(workingBuilder.Length - 1, 1);  //remove last comma
                                    workingBuilder.Append(");");
                                    workingBuilder.Append(colorString);
                                    workingBuilder.Append("var polygon" + originalPolyNum + " = new m.Polygon(vertices" + originalPolyNum + ",{fillColor: polygoncolor, strokeColor: '255,0,0,0', strokeThickness: .25});");
                                    workingBuilder.Append("mapName.entities.push(polygon" + originalPolyNum + ");");
                                    //Now add district number
                                    var centerPoint = GetLabelLocation(clippedGeom);
                                    workingBuilder.Append("var pushpin;");
                                    workingBuilder.Append("var pushpinOptions;");
                                    workingBuilder.Append("pushpinOptions = { icon: '../images/blank.png', text: '" + pm.name + "', height: 20, width: 20, typeName: 'districtLabel'};");
                                    workingBuilder.Append("pushpin = new m.Pushpin(new m.Location(" + centerPoint.Latitude + ", " + centerPoint.Longitude + "), pushpinOptions);");
                                    workingBuilder.Append("mapName.entities.push(pushpin);");
                                }
                            } // if not empty
                            originalPolyNum++;
                        }//foreach (var p in polyQuery)
                        workingBuilder.Append("}");
                        workingBuilder.Append("setTimeout('AddPoly" + mapName + mgNum + "(" + mapName + ")', 1);");
                    } //(districtBoxGeom.STEnvelope().STIntersects(mapBoxGeom.STEnvelope()))
                    int nextMg = mgNum + 1;
                    mgNum++;
                }//mg w/ the polys                
            } //foreach (var pm in pmList)
            returnString = workingBuilder.ToString();
            return returnString;
        }

        public static SqlGeometry CreateClippedPolyFromBoundingBox(IList<Point> PolyPts, SqlGeometry mapBoxGeom)
        {
            SqlGeometry newGeom = new SqlGeometry();
            StringBuilder wktBuilder = new StringBuilder();
            try
            {
                double startX = 0.0, startY = 0.0;
                wktBuilder.Append("POLYGON((");

                for (int p = 0; p < PolyPts.Count; p++)
                {
                    var point = PolyPts[p];
                    double stx = double.Parse(point.Longitude.ToString());
                    double sty = double.Parse(point.Latitude.ToString());
                    wktBuilder.Append("" + stx + " " + sty + ",");
                    if (p == 0)
                    {
                        startX = stx;
                        startY = sty;
                    }
                }
                wktBuilder.Append("" + startX + " " + startY + "))");
                SqlChars newGWkt = new SqlChars(wktBuilder.ToString());
                newGeom = SqlGeometry.STGeomFromText(newGWkt, 4326).MakeValid();
                if (newGeom.STAsText().ToSqlString().ToString().Contains("GEOMETRYCOLLECTION"))
                //only want to return a polygon. will need to adjust this to handle multi-polygons
                {
                    int geometryCount = (int)newGeom.STNumGeometries();
                    SqlGeometry geomToKeep = new SqlGeometry();
                    for (int geomIndex = 1; geomIndex <= newGeom.STNumGeometries(); geomIndex++)
                    {
                        SqlGeometry childGeom = newGeom.STGeometryN(geomIndex);
                        if (childGeom.STAsText().ToSqlString().ToString().Contains("POLYGON"))
                        {
                            geomToKeep = childGeom;
                        }
                    }
                    newGeom = geomToKeep;
                }
                //Do this if only wanting to return exterior ring
                //string exteriorStringWkt = newGeom.STExteriorRing().STAsText().ToSqlString().ToString().Replace("LINESTRING", "POLYGON(");
                //exteriorStringWkt = exteriorStringWkt + ")";
                //newGWkt = new SqlChars(exteriorStringWkt);
                //newGeom = SqlGeometry.STGeomFromText(newGWkt, 4326).MakeValid();
            }
            catch (Exception ex)
            {
                string test = ex.ToString();
            }

            return newGeom.STIntersection(mapBoxGeom.STEnvelope()).MakeValid();
        }


        /// <summary>
        /// Gets the label location.
        /// See the sql spatial fourum at http://social.msdn.microsoft.com/Forums/en-US/sqlspatial/thread/4e9f687e-ee26-437a-9b71-765d381171b6
        /// The methodology used is to get the two lines that intersect the shape centered on the bounding box
        /// and determine which one is the best fit.  If not best fit is found within the shape based on this method
        /// then the centroid is returned
        /// </summary>
        /// <param name="geom">The geom.</param>
        /// <returns></returns>
        public static Point GetLabelLocation(SqlGeometry geom)
        {
            SqlGeometry returnGeom = new SqlGeometry();
            Point returnPoint = new Point();
            SqlGeometry labelPtGeom;
            SqlGeometry boundingBox = geom.STEnvelope();
            try
            {
                //First find the latitudinal label point
                var NWLat = (double)boundingBox.STPointN(4).STY;
                var NWLon = (double)boundingBox.STPointN(4).STX;
                var SELat = (double)boundingBox.STPointN(2).STY;
                var SELon = (double)boundingBox.STPointN(2).STX;
                var midY = ((NWLat - SELat) / 2) + SELat;
                var midX = ((NWLon - SELon) / 2) + SELon;
                var sc = new SqlChars("LINESTRING(" + NWLon + " " + midY + ", " + SELon + " " + midY + ")");
                SqlGeometry latLine = SqlGeometry.STGeomFromText(sc, 4326);
                SqlGeometry latLineIntersect = latLine.STIntersection(geom);
                if (latLineIntersect.STNumGeometries() > 1) //handle multi-linestrings
                {
                    double longestLineMeasure = 0.0;
                    SqlGeometry lineSegmentToKeep = new SqlGeometry();
                    int geometryCount = (int)latLineIntersect.STNumGeometries();
                    for (int geomIndex = 1; geomIndex <= latLineIntersect.STNumGeometries(); geomIndex++)
                    {
                        SqlGeometry childGeom = latLineIntersect.STGeometryN(geomIndex);
                        if (childGeom.STLength() > longestLineMeasure)
                        {
                            lineSegmentToKeep = childGeom;
                            longestLineMeasure = (double)childGeom.STLength();
                        }
                    }
                    latLineIntersect = lineSegmentToKeep;
                }
                sc = new SqlChars("LINESTRING(" + midX + " " + NWLat + ", " + midX + " " + SELat + ")");
                SqlGeometry lonLine = SqlGeometry.STGeomFromText(sc, 4326);
                SqlGeometry lonLineIntersect = lonLine.STIntersection(geom);
                if (lonLineIntersect.STNumGeometries() > 1) //handle multi-linestrings
                {
                    double longestLineMeasure = 0.0;
                    SqlGeometry lineSegmentToKeep = new SqlGeometry();
                    int geometryCount = (int)lonLineIntersect.STNumGeometries();
                    for (int geomIndex = 1; geomIndex <= lonLineIntersect.STNumGeometries(); geomIndex++)
                    {
                        SqlGeometry childGeom = lonLineIntersect.STGeometryN(geomIndex);
                        if (childGeom.STLength() > longestLineMeasure)
                        {
                            lineSegmentToKeep = childGeom;
                            longestLineMeasure = (double)childGeom.STLength();
                        }
                    }
                    lonLineIntersect = lineSegmentToKeep;
                }
                if (latLineIntersect.STLength() > lonLineIntersect.STLength())
                {
                    midY = (((double)latLineIntersect.STStartPoint().STY - (double)latLineIntersect.STEndPoint().STY) / 2) + (double)latLineIntersect.STEndPoint().STY;
                    midX = (((double)latLineIntersect.STStartPoint().STX - (double)latLineIntersect.STEndPoint().STX) / 2) + (double)latLineIntersect.STEndPoint().STX;
                    sc = new SqlChars("POINT(" + midX + " " + midY + ")");
                    labelPtGeom = SqlGeometry.STGeomFromText(sc, 4326);
                }
                else
                {
                    midY = (((double)lonLineIntersect.STStartPoint().STY - (double)lonLineIntersect.STEndPoint().STY) / 2) + (double)lonLineIntersect.STEndPoint().STY;
                    midX = (((double)lonLineIntersect.STStartPoint().STX - (double)lonLineIntersect.STEndPoint().STX) / 2) + (double)lonLineIntersect.STEndPoint().STX;
                    sc = new SqlChars("POINT(" + midX + " " + midY + ")");
                    labelPtGeom = SqlGeometry.STGeomFromText(sc, 4326);
                }
                if (labelPtGeom.STWithin(geom))
                {
                    returnGeom = labelPtGeom;
                }
                else
                {
                    returnGeom = geom.STCentroid();
                }
                returnPoint.Latitude = (double)returnGeom.STPointN(1).STY;
                returnPoint.Longitude = (double)returnGeom.STPointN(1).STX;
                return returnPoint;
            }
            catch (Exception ex)
            {
                string theErrorString = ex.ToString();
                returnGeom = geom.STCentroid();
                return returnPoint;
            }
        }


        public static SqlGeometry simplePolygonCentroid(SqlGeometry districtBoxGeom)
        {
            SqlGeometry returnPoint = districtBoxGeom.STPointOnSurface();
            return returnPoint;
        }



        /// <summary>
        /// This method parses the given coordinates string.
        /// </summary>
        /// <param name="coordinates">String with coordinates to be parsed</param>
        /// <returns>List of points contained in the given string</returns>
        public static IList<Point> ParseCoordinates(string coordinates)
        {
            List<Point> points = new List<Point>();

            if (string.IsNullOrEmpty(coordinates) || coordinates.Trim().Length == 0)
                return points;

            // Removes the spaces inside the touples
            while (coordinates.Contains(", "))
            {
                coordinates = coordinates.Replace(", ", ",");
            }

            // Splits the tuples
            string[] coordinate = coordinates.Trim().Split(' ', '\t', '\n');
            if (coordinate == null)
                return points;

            // Process each tuple
            foreach (string p in coordinate)
            {
                string tp = p.Trim();
                if (tp.Length == 0)
                    continue;

                string[] cords = tp.Split(',');

                try
                {
                    double longitude = double.Parse(cords[0], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture);
                    double latitude = double.Parse(cords[1], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture);
                    double? altitude = null;

                    if (cords.Length == 3)  // the altitude is optional
                    {
                        altitude = double.Parse(cords[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture);
                    }

                    Point point = new Point();
                    point.Longitude = longitude;
                    point.Latitude = latitude;
                    point.Altitude = altitude;

                    // If point is the same as the previous point then skip it
                    if (points.Count > 0 && points[points.Count - 1].Equals(point))
                        continue;

                    points.Add(point);
                }
                catch (Exception ex)
                {
                    string test = ex.ToString();
                    //throw new KMLException("Coordinate is in wrong format: " + tp, exc);
                }
            }

            return points;
        }


    }
}